CurrentWave = 0
CurrentWaveTimeLeft = 0
WaveRunning = false
GameHasEnded = false

-- Checks if there are players in the server, If not.. Halts the game...
function GameStartCheck()
	local players = ents.FindByClass("player")
	if #players <= 0 then
		WaveRunning = false
		for k, v in pairs(ents.FindByClass("npc_*")) do
			v:Remove()
			print("Removed NPC: " .. v:GetClass() .. " because there are no players")
		end
	else
		WaveRunning = true
	end
end
timer.Create( "inv_gamestartcheck", 1, 0, GameStartCheck)

function WaveTimerCountdown()
	if WaveRunning == true and GameHasEnded == false then
		CurrentWaveTimeLeft = CurrentWaveTimeLeft - 1	
		if CurrentWaveTimeLeft <= 0 then
			NextWave()
		end
	end
end
timer.Create( "inv_wavetimercount", 1, 0, WaveTimerCountdown)

-- Send the wave info to the client every 5 seconds, The client fills in the gaps. Keeps network usage down a bit
function WaveInfoClientUpdate()
	SendWaveInfoToClient(CurrentWaveTimeLeft, CurrentWave, WaveRunning, GameHasEnded)
end
timer.Create( "inv_waveclientupdate", INV_CLIENTUPDATEINTERVAL, 0, WaveInfoClientUpdate)

-- Uses the wave settings to try spawn an NPC every n Seconds.
local SpawnThink_ReTime = 0
function SpawnThink()
	if WaveRunning == true and GameHasEnded == false then
		if (CurTime() >= SpawnThink_ReTime) then
			SpawnCurrentWaveNPC()
			SpawnThink_ReTime = CurTime() + INV_WAVES[CurrentWave][INV_WAVE_SPAWNDELAY]
		end
	end
end
hook.Add("Think", "inv_spawnthink", SpawnThink)

function NextWave()
	-- Stop the current wave
	WaveRunning = false
	
	-- Get rid of any left over NPCs, Kill them
	for k, v in pairs(ents.FindByClass("npc_*")) do
		if(v:GetClass() == "npc_turret_floor") then
			-- No remove, gap here for extra functions later
		else
			v:Remove()
		end
	end
	
	-- Resupply Everyone...
	for _,ply in pairs(team.GetPlayers(TEAM_LIVING)) do
		ply:StripAmmo()
		--Resupply Ammo
		
			for k, v in pairs(ply:GetWeapons()) do
				if(v:GetClass() != "weapon_crowbar")then
					ply:GiveAmmo(v.Primary.ClipSize, v:GetPrimaryAmmoType( ))
				end
			end
	end
	
	
	if GameHasEnded == false then
	-- Move onto the next wave, If it is not the last wave
		if CurrentWave + 1 <= #INV_WAVES then
			CurrentWave = CurrentWave + 1
			CurrentWaveTimeLeft = INV_WAVES[CurrentWave][INV_WAVE_TIMELIMIT]
			
			-- Wave in server name...
			if(INV_SHOWWAVEINNAME == true)then	
				RunConsoleCommand("hostname", INV_SERVERNAME .. " Wave " .. tostring(CurrentWave) .. " of " .. tostring(#INV_WAVES))
			end
			
			for _, ply in ipairs( player.GetAll() ) do
				if ply:Team() == TEAM_LIVING then
					SendMessageToPlayerChat(ply, "Wave " .. tostring(CurrentWave) .. " has begun, you got " .. INV_MONEYPREFIX .. tostring(INV_WAVES[CurrentWave - 1][INV_WAVE_MONEY]) .. " for staying alive")
					ply:AddMoney(INV_WAVES[CurrentWave - 1][INV_WAVE_MONEY])
					
					-- BONUSES
					if(INV_ENABLEBONUSES)then
						if(#team.GetPlayers(TEAM_SPEC) == 0)then
							SendMessageToPlayerChat(ply, "You also got a " .. INV_MONEYPREFIX .. tostring(INV_WAVES[CurrentWave - 1][INV_WAVE_MONEY] * INV_ALLALIVEBONUS) .. " bonus for everyone being alive")
							ply:AddMoney(INV_WAVES[CurrentWave - 1][INV_WAVE_MONEY] * INV_ALLALIVEBONUS)
						end
					end
					-- /BONUSES
				else
					SendMessageToPlayerChat(ply, "Wave " .. tostring(CurrentWave) .. " has begun, you got nothing because you died")
				end
			end
			
			-- Make the spectators live again!
			for _,ply in pairs(team.GetPlayers(TEAM_SPEC)) do
				ply:SetTeam(TEAM_LIVING)
				ply:KillSilent()
			end
		
			SpawnThink_ReTime = CurTime() + INV_WAVES[CurrentWave][INV_WAVE_SPAWNDELAY]
		
			-- Begin the wave, Update the client, Done
			WaveRunning = true
			WaveInfoClientUpdate()
		
			print("NEW WAVE: " .. CurrentWave .. " " .. CurrentWaveTimeLeft)
		else
			-- That was the last wave, Do win Conditions and such
			GameOver()
			print("Game Finished!")
		end
	end
end

function GameOver()
	local powercore = ents.FindByClass("inv_powercore")[1]

	for k, v in pairs(ents.FindByClass("npc_*")) do
			v:Remove()
	end

	GameHasEnded = true
	WaveRunning = false
	WaveInfoClientUpdate()
	
	for _, ply in ipairs( player.GetAll() ) do
		ply:Freeze( true )
		ply:StripWeapons()
		if(powercore:Health() > 0)then
			if(team.NumPlayers(TEAM_LIVING) == 0) then
				SendMessageToPlayerChat(ply, "Everyone Died, You lost!")
				SendMessageToPlayerChat(ply, "Changing level in 5 seconds")
			else
				SendMessageToPlayerChat(ply, "Your power core survived, you won!")
				SendMessageToPlayerChat(ply, "You gained " .. INV_MONEYPREFIX .. (powercore:Health() * INV_COREMONEYMULT) .. " for winning!")
				SendMessageToPlayerChat(ply, "Changing level in 5 seconds")
				ply:AddMoney(powercore:Health() * INV_COREMONEYMULT) -- Give them money for winning
			end
		else
			
			
			SendMessageToPlayerChat(ply, "Your power core did not survive, you lost!")
			SendMessageToPlayerChat(ply, "Changing level in 5 seconds")
		end
	end
	
	local nextmap = INV_MAPS[math.random(1,#INV_MAPS)]
			
	timer.Create( "mapchangedelay", 5, 0, function()
				RunConsoleCommand("changelevel", nextmap)
			end )
	

 
	
end

function SpawnCurrentWaveNPC()
	-- Find all current NPCs, that aren't turrets
	npclist = {}
	for k, v in pairs(ents.FindByClass("npc_*")) do
		if(v:GetClass() == "npc_turret_floor")then
			--- ignore
		else
			table.insert(npclist, v)
		end
	end
	
	--PrintTable(npclist)
	

	-- Find a spawn point
	local Spawns = ents.FindByClass("invasion_spawn")
	local RandomNum = math.Round(math.Rand(1, #Spawns))
	local RandomSpawn = Spawns[RandomNum]

	-- Create an NPC at that spawn if the limit has not been reached.
	if(#npclist < INV_WAVES[CurrentWave][INV_WAVE_MAXAMOUNT]) then

		npc = ents.Create (INV_WAVES[CurrentWave][INV_WAVE_CLASSNAME])
		npc:SetPos(RandomSpawn:GetPos() + Vector(math.Rand(-(INV_SPAWNRADIUS / 2),(INV_SPAWNRADIUS / 2)),math.Rand(-(INV_SPAWNRADIUS / 2),(INV_SPAWNRADIUS / 2)),0))

		if INV_WAVES[CurrentWave][INV_WAVE_WEAPON] != nil then
			npc:SetKeyValue ("additionalequipment", INV_WAVES[CurrentWave][INV_WAVE_WEAPON])
		end
		npc:SetKeyValue("spawnflags","8192")
		npc:Spawn()
		npc:SetMaxHealth(INV_WAVES[CurrentWave][INV_WAVE_HEALTH])
		npc:SetHealth(INV_WAVES[CurrentWave][INV_WAVE_HEALTH])
		npc:SetCollisionGroup (3)
		npc:SetCurrentWeaponProficiency( INV_WAVES[CurrentWave][INV_WAVE_PROFICIENCY] )
		
		--PrintTable(ents.FindByClass("npc_*"))
		
		-- Each NPC hates something different
		-- Some will want to attack the power core first, others the players.
		
		local powercore = ents.FindByClass("inv_powercore")[1]
		local rando = math.random(1,2)
		if rando == 1 then
			--print("This NPC hates players")
			npc:AddEntityRelationship(powercore, D_HT, 1 )
			npc:AddRelationship("player D_HT 100")
		else
			--print("This NPC hates powercores")
			npc:AddEntityRelationship(powercore, D_HT, 100 )
			npc:AddRelationship("player D_HT 1")
		end
		
		npc:AddRelationship("npc_turret_floor D_HT 50")
		
		-- Tell the NPC where the powercore is...
		npc:UpdateEnemyMemory(powercore,powercore:GetPos())
		npc:NavSetGoal( powercore:GetPos() )
	end
end